home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Atari Mega Archive 1
/
Atari Mega Archive - Volume 1.iso
/
gnu
/
fpu881
/
src6.zoo
/
doprnt.c
< prev
next >
Wrap
C/C++ Source or Header
|
1991-09-24
|
18KB
|
743 lines
/*
* Copyright (c) 1988 Regents of the University of California.
* All rights reserved.
*
* Redistribution and use in source and binary forms are permitted
* provided that the above copyright notice and this paragraph are
* duplicated in all such forms and that any documentation,
* advertising materials, and other materials related to such
* distribution and use acknowledge that the software was developed
* by the University of California, Berkeley. The name of the
* University may not be used to endorse or promote products derived
* from this software without specific prior written permission.
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
* WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*/
/*
* minorly customized for gcc lib
* ++jrb
* and for the sfp004
* mjr++
*/
static unsigned long
__notanumber[2] = { 0x7fffffffL, 0xffffffffL }; /* ieee NAN */
#define NAN (*((double *)&__notanumber[0]))
#ifdef LIBC_SCCS
static char sccsid[] = "@(#)doprnt.c 5.37 (Berkeley) 3/26/89";
#endif /* LIBC_SCCS */
#include <sys/types.h>
#include <stdarg.h>
#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include <limits.h>
#include <math.h>
#ifndef __GNUC__ /* gcc lib has these typedefs in sys/types.h */
typedef unsigned char u_char;
typedef unsigned long u_long;
#endif
/* 11-bit exponent (VAX G floating point) is 308 decimal digits */
#define MAXEXP 308
/* 128 bit fraction takes up 39 decimal digits; max reasonable precision */
#define MAXFRACT 39
#define DEFPREC 6
#define BUF (MAXEXP+MAXFRACT+1) /* + decimal point */
#define PUTC(ch) if( fputc(ch, fp) == EOF ) return EOF;
#define ARG(basetype) \
_ulong = flags&LONGINT ? va_arg(argp, long basetype) : \
flags&SHORTINT ? (short basetype)va_arg(argp, short) : \
va_arg(argp, int)
#define TEN_MUL(X) ((((X) << 2) + (X)) << 1)
#define todigit(c) ((c) - '0')
#define tochar(n) ((n) + '0')
#define LONGINT 0x01 /* long integer */
#define LONGDBL 0x02 /* long double; unimplemented */
#define SHORTINT 0x04 /* short integer */
#define ALT 0x08 /* alternate form */
#define LADJUST 0x10 /* left adjustment */
#define ZEROPAD 0x20 /* zero (as opposed to blank) pad */
#define HEXPREFIX 0x40 /* add 0x or 0X prefix */
#ifndef __NO_FLOAT__
#define __FLOATS__ 1
#endif
#ifdef __FLOATS__
#ifdef __STDC__
static char *exponent(char *, int, int);
static char *round(double, int *, char *, char *, int, char *);
static int cvt(double, int, int, char *, int, char *, char *);
#else
static char *exponent();
static char *round();
static int cvt();
#endif
#endif
#ifdef __GNUC__
#define _ICONV(NUMBER, BASE, BUF) \
{ \
short i; \
if(NUMBER <= 65535L) \
{ \
do \
{ \
__asm__ volatile(" \
divu %3,%2; \
swap %0; \
movw %0,%1; \
clrw %0; \
swap %0" \
: "=d"((long)NUMBER), "=g"(i) \
: "0"((long)NUMBER), "g"((short)BASE)); \
*--BUF = digs[i]; \
} while(NUMBER); \
} \
else \
{ \
extern unsigned long __udivsi3(); /* quot = d0, rem = d1 */ \
do \
{ \
__asm__ volatile(" \
movl %3,sp@-; \
movl %2,sp@-; \
jsr ___udivsi3; \
movl d0,%0; \
movw d1,%1; \
addqw #8,sp" \
: "=g"((long)NUMBER), "=g"(i) \
: "0"((long)NUMBER), "g"((long)BASE) \
: "d0", "d1", "a0", "a1"); \
*--BUF = digs[i]; \
} while(NUMBER); \
} \
}
#endif /* __GNUC__ */
int _doprnt(fp, fmt0, argp)
register FILE *fp;
u_char *fmt0;
va_list argp;
{
register u_char *fmt; /* format string */
register int ch; /* character from fmt */
register int cnt; /* return value accumulator */
register int n; /* random handy integer */
register char *t; /* buffer pointer */
double _double; /* double precision arguments %[eEfgG] */
u_long _ulong; /* integer arguments %[diouxX] */
short base; /* base for [diouxX] conversion */
short dprec; /* decimal precision in [diouxX] */
short fieldsz; /* field size expanded by sign, etc */
short flags; /* flags as above */
short fpprec; /* `extra' floating precision in [eEfgG] */
short prec; /* precision from format (%.3d), or -1 */
short realsz; /* field size expanded by decimal precision */
short size; /* size of converted field or string */
short width; /* width from format (%8d), or 0 */
char sign; /* sign prefix (' ', '+', '-', or \0) */
char softsign; /* temporary negative sign for floats */
char *digs; /* digits for [diouxX] conversion */
char buf[BUF]; /* space for %c, %[diouxX], %[eEfgG] */
fmt = fmt0;
digs = "0123456789abcdef";
for (cnt = 0;; ++fmt) {
if (!(ch = *fmt))
return (cnt);
if (ch != '%') {
PUTC(ch);
continue;
}
flags = 0; dprec = 0; fpprec = 0; width = 0;
prec = -1;
sign = '\0';
rflag: switch (*++fmt) {
case ' ':
/*
* ``If the space and + flags both appear, the space
* flag will be ignored.''
* -- ANSI X3J11
*/
if (!sign)
sign = ' ';
goto rflag;
case '#':
flags |= ALT;
goto rflag;
case '*':
/*
* ``A negative field width argument is taken as a
* - flag followed by a positive field width.''
* -- ANSI X3J11
* They don't exclude field widths read from args.
*/
if ((width = (short)(va_arg(argp, int))) >= 0)
goto rflag;
width = -width;
/* FALLTHROUGH */
case '-':
flags |= LADJUST;
goto rflag;
case '+':
sign = '+';
goto rflag;
case '.':
if (*++fmt == '*')
n = va_arg(argp, int);
else {
n = 0;
while (isascii(*fmt) && isdigit(*fmt))
n = TEN_MUL(n) + todigit(*fmt++);
--fmt;
}
prec = n < 0 ? -1 : n;
goto rflag;
case '0':
/*
* ``Note that 0 is taken as a flag, not as the
* beginning of a field width.''
* -- ANSI X3J11
*/
flags |= ZEROPAD;
goto rflag;
case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
n = 0;
do {
n = TEN_MUL(n) + todigit(*fmt);
} while (isascii(*++fmt) && isdigit(*fmt));
width = n;
--fmt;
goto rflag;
case 'L':
flags |= LONGDBL;
goto rflag;
case 'h':
flags |= SHORTINT;
goto rflag;
case 'l':
flags |= LONGINT;
goto rflag;
case 'c':
*(t = buf) = va_arg(argp, int);
size = 1;
sign = '\0';
goto pforw;
case 'D':
flags |= LONGINT;
/*FALLTHROUGH*/
case 'd':
case 'i':
ARG(int);
if ((long)_ulong < 0) {
_ulong = -_ulong;
sign = '-';
}
base = 10;
goto number;
#ifdef __FLOATS__
case 'e':
case 'E':
case 'f':
case 'g':
case 'G':
_double = va_arg(argp, double);
/* mjr: check for NANs */
if(_double == NAN) {
t = strcpy(t, " Not A Number ");
size = strlen(t);
goto pforw;
}
/*
* don't do unrealistic precision; just pad it with
* zeroes later, so buffer size stays rational.
*/
if (prec > MAXFRACT) {
if (*fmt != 'g' && *fmt != 'G' || (flags&ALT))
fpprec = prec - MAXFRACT;
prec = MAXFRACT;
}
else if (prec == -1)
prec = DEFPREC;
/*
* softsign avoids negative 0 if _double is < 0 and
* no significant digits will be shown
*/
if (_double < 0) {
softsign = '-';
_double = -_double;
}
else
softsign = 0;
/* mjr: check for +-INFINITY */
if(_double == HUGE) {
if(softsign == 0)
t = strcpy(t, " Infinity ");
else
t = strcpy(t, " -Infinity ");
size = strlen(t);
goto pforw;
}
/*
* cvt may have to round up past the "start" of the
* buffer, i.e. ``intf("%.2f", (double)9.999);'';
* if the first char isn't NULL, it did.
*/
*buf = (char)NULL;
size = cvt(_double, (int)prec, (int)flags, &softsign,
*fmt, buf, buf + (int)sizeof(buf));
if (softsign)
sign = '-';
t = *buf ? buf : buf + 1;
goto pforw;
#endif /* __FLOATS__ */
case 'n':
if (flags & LONGINT)
*va_arg(argp, long *) = cnt;
else if (flags & SHORTINT)
*va_arg(argp, short *) = cnt;
else
*va_arg(argp, int *) = cnt;
break;
case 'O':